import requests as req  # 导入requests库，用于进行HTTP请求
import time as tm  # 导入time库，用于处理时间相关操作

# 快速模幂运算函数，用于密码加密
def fast_mod_exp(base, exp, mod):
    result = 1
    while exp > 0:
        if exp & 1:
            result = result * base % mod
        exp //= 2
        base = base * base % mod
    return result

# 将字符串转换为数值的函数
def str_to_num(s):
    return sum(ord(c) * 256 ** (len(s) - i - 1) for i, c in enumerate(s))

# 对密码进行加密的函数
def encode_password(password):
    exp = 65537
    mod = 135261828916791946705313569652794581721330948863485438876915508683244111694485850733278569559191167660149469895899348939039437830613284874764820878002628686548956779897196112828969255650312573935871059275664474562666268163936821302832645284397530568872432109324825205567091066297960733513602409443790146687029
    return hex(fast_mod_exp(str_to_num(password), exp, mod))

# 加入游戏的函数
def join_game(user, password):
    url = 'http://183.175.12.27:8002/join_game'  # 游戏服务器的URL
    params = {'user': user, 'password': password, 'data_type': 'json'}  # 请求参数
    response = req.get(url, params=params)  # 发送GET请求
    print(f"Joined new game: {response.text}")  # 打印加入游戏的响应信息
    return response.json()  # 返回JSON格式的响应数据

# 检查游戏状态的函数
def check_game(game_id):
    url = f'http://183.175.12.27:8002/check_game/{game_id}'  # 检查游戏状态的URL
    response = req.get(url)  # 发送GET请求
    return response.json()  # 返回JSON格式的响应数据

# 执行游戏移动的函数
def play_move(user, password, game_id, coord):
    url = f'http://183.175.12.27:8002/play_game/{game_id}'  # 执行游戏移动的URL
    params = {'user': user, 'password': password, 'data_type': 'json', 'coord': coord}  # 请求参数
    req.get(url, params=params)  # 发送GET请求

# 将坐标转换为索引的函数
def coord_to_index(coord):
    return (ord(coord[0]) - ord('a')) * 16 + ord(coord[1]) - ord('a')

# 生成所有可能坐标的函数
def all_coords():
    return [chr(i + 97) + chr(j + 97) for i in range(15) for j in range(16)]

# 将线路转换为指定字符的函数
def convert_line(line, key_char):
    return line.replace('x', 'M').replace('o', 'O').replace('.', '.').replace(key_char, 'C')

# 获取水平线路的函数
def get_horizontal(board, row, col):
    line = []
    for c in range(col - 4, col + 5):
        if 0 <= c < 15:
            if c == col:
                line.append('C')
            else:
                line.append(board[row][c])
        else:
            line.append('')
    return convert_line(''.join(line), 'C')

# 获取垂直线路的函数
def get_vertical(board, row, col):
    line = []
    for r in range(row - 4, row + 5):
        if 0 <= r < 15:
            if r == row:
                line.append('C')
            else:
                line.append(board[r][col])
        else:
            line.append('')
    return convert_line(''.join(line), 'C')

# 获取从左上到右下对角线线路的函数
def get_diagonal_lr(board, row, col):
    line = []
    for i in range(-4, 5):
        r = row + i
        c = col + i
        if 0 <= r < 15 and 0 <= c < 15:
            if r == row and c == col:
                line.append('C')
            else:
                line.append(board[r][c])
        else:
            line.append('')
    return convert_line(''.join(line), 'C')

# 获取从右上到左下对角线线路的函数
def get_diagonal_rl(board, row, col):
    line = []
    for i in range(-4, 5):
        r = row + i
        c = col - i
        if 0 <= r < 15 and 0 <= c < 15:
            if r == row and c == col:
                line.append('C')
            else:
                line.append(board[r][c])
        else:
            line.append('')
    return convert_line(''.join(line), 'C')

# 解析游戏板块的函数
def parse_board(board_str):
    return [list(board_str[i * 16:(i + 1) * 16]) for i in range(15)]

# 确定当前轮次的函数
def determine_turn(order):
    return 'MO' if (len(order) // 2) % 2 == 0 else 'OM'

# 设置评分规则的函数
def scoring_rules():
    return {
        ("CMMMM", "MCMMM", "MMCMM", "MMMCM", "MMMMC"): 10000,
        ("COOOO", "OCOOO", "OOCOO", "OOOCO", "OOOOC"): 6000,
        (".CMMM.", ".MCMM.", ".MMCM.", ".MMMC."): 5000,
        ("COOO.", ".OOOC", ".OOCO.", ".OCOO."): 2500,
        ("OCMMM.", "OMCMM.", "OMMCM.", "OMMMC.", ".CMMMO", ".MCMMO", ".MMCMO", ".MMMCO"): 2000,
        (".MMC.", ".MCM.", ".CMM."): 400,
        (".OOC", "COO.", "MOOOC", "COOOM"): 400,
        (".MMCO", ".MCMO", ".CMMO", "OMMC.", "OMCM.", "OCMM.", "MOOC", "COOM"): 200,
        (".MC.", ".CM."): 50,
        ('.'): 1
    }

# 获取最佳移动的函数
def best_move(order, rules, coords):
    board = '...............\n' * 15  # 初始游戏板块状态
    step = 0
    BW = determine_turn(order)  # 确定当前轮次

    # 根据游戏历史设置游戏板块状态
    for i in range(0, len(order), 2):
        index = coord_to_index(order[i:i + 2])
        board = board[:index] + BW[step % 2] + board[index + 1:]
        step += 1
    print(board)  # 打印当前游戏板块状态
    parsed_board = parse_board(board)  # 解析游戏板块
    max_points, best_coord = 0, ''  # 初始化最高分和最佳坐标
    for i in range(len(board)):
        if board[i] == '.':
            coord = coords[i]  # 获取当前坐标
            row, col = ord(coord[0]) - ord('a'), ord(coord[1]) - ord('a')  # 转换坐标为行列数
            lines = [get_horizontal(parsed_board, row, col), get_vertical(parsed_board, row, col),
                     get_diagonal_lr(parsed_board, row, col), get_diagonal_rl(parsed_board, row, col)]  # 获取四个方向的线路
            lines_str = ','.join(lines)  # 将线路列表转换为字符串
            points = sum(value * lines_str.count(pattern) for patterns, value in rules.items() for pattern in patterns)  # 根据规则计算分数

            if points > max_points:
                max_points, best_coord = points, coord  # 更新最高分和最佳坐标

    print(f"Best move: {best_coord} with {max_points} points")  # 打印最佳移动和得分
    return best_coord  # 返回最佳坐标

# 初始化用户和密码信息
user = '0211423595'
password = 'ys100820'
encoded_pass = encode_password(password)  # 加密密码
rules = scoring_rules()  # 设置评分规则
coords = all_coords()  # 生成所有可能的坐标

# 加入游戏并获取游戏ID
game_info = join_game(user, encoded_pass)
game_id = game_info["game_id"]

print("Looking for game partner...")
state = check_game(game_id)

# 循环检查游戏状态，直到游戏准备好开始
while state['ready'] == "False":
    state = check_game(game_id)
    print(state['ready'], end=" ")  # 打印游戏准备状态
    tm.sleep(5)  # 等待5秒继续检查

opponent = state['creator'] if state['creator'] != user else state['opponent_name']  # 获取对手的用户名

# 循环进行游戏
while state['ready'] == "True":
    if state['current_turn'] == user:  # 如果轮到当前用户
        order = state['board']  # 获取当前游戏板块状态
        coord = best_move(order, rules, coords)  # 计算最佳移动坐标
        play_move(user, encoded_pass, game_id, coord)  # 执行最佳移动
        print(f"Played at {coord}")  # 打印执行的移动位置
    else:
        print(f"Waiting for {opponent} to play")  # 等待对手进行移动

    tm.sleep(5)  # 等待5秒继续进行游戏
    state = check_game(game_id)  # 更新游戏状态

    if state['winner'] != "None":  # 如果有赢家产生
        print(f"The winner is {state['winner']}")  # 打印赢家信息
        break  # 结束游戏循环
